use std::thread;
use std::time::Duration;

fn main() {
    let susv = 10;
    let srn = 7;
    generate_workout(
        susv,
        srn
    )
}

// fn simulate_expensive_calculation(intensity:u32)->u32{
//     println!("Calculating Slowly");
//     thread::sleep(Duration::from_secs(2));
//     intensity
// }

fn generate_workout(i:u32, r:u32){
    // let extm = simulate_expensive_calculation(i);
    // #[derive!(Debug)]
    // let simulate_closure = |num|->u32{
    //     println!("Calculating Slowly");
    //     thread::sleep(Duration::from_secs(5));
    //     num
    // };

    let mut simulate_closure = Cacher::new(|num|{
            println!("Calculating Slowly");
            thread::sleep(Duration::from_secs(2));
            num
    });

    // let enm = simulate_closure.value(i);

    if i<25{
        // println!("Today, do {} pushups!", simulate_closure(i));
        // println!("Next, do {} situps!",simulate_closure(i));
        println!("Today, do {} pushups!", simulate_closure.value(i));
        println!("Nextm, do {} situps!",simulate_closure.value(i));
    }else {
        if r==3{
            println!("Take a break today! Remember to stay hydrated!");
        }else {
            println!("Today, run for {} minites!", simulate_closure.value(i));
            // println!("Today, run for {} minites!", simulate_closure(i));
        }
    }
}

struct Cacher<T>
where T:Fn(u32)->u32
{
    calculation: T,
    value: Option<u32>
}

impl <T> Cacher<T>
where T:Fn(u32)->u32
{
    fn new(calculation:T)->Cacher<T>{
        Cacher{
            calculation,
            value: None
        }
    }

    fn value(&mut self, arg:u32)->u32{
        match self.value {
            Some(v)=>v,
            None=>{
                let v = (self.calculation)(arg);
                self.value = Some(v);
                v
            },
        }
    }
}

#[test]
fn t(){
    let mut c = Cacher::new(|a| a);
    let v1 = c.value(1);
    let v2 = c.value(2);
    assert_eq!(v2, 2);
}
